﻿#include "USART1_DMA.h"
#include "M2P_Serial_Console.h"
#include "delay.h"
#include "string.h"
#include <stdarg.h>

//USART1_MAX_TX_LEN和USART1_MAX_RX_LEN在头文件进行了宏定义，分别指USART1最大发送长度和最大接收长度
u8 USART1_TX_BUF[USART1_MAX_TX_LEN]; 	//发送缓冲,最大USART1_MAX_TX_LEN字节
u8 m2p_u1rxbuf[USART1_MAX_RX_LEN];			//发送数据缓冲区1
u8 m2p_u2rxbuf[USART1_MAX_RX_LEN];			//发送数据缓冲区2
u8 m2p_witchbuf;                  		//标记当前使用的是哪个缓冲区,0：使用u1rxbuf；1：使用u2rxbuf
u8 USART1_TX_FLAG;					//USART1发送标志，启动发送时置1,空闲时为0
u8 USART1_RX_FLAG;					//USART1接收标志，启动接收时置1,空闲时为0

void DMA_FOR_USART1_Init(void)
{
	DMA_InitTypeDef DMA1_Init;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);						//使能DMA1时钟

	//DMA_USART1_RX  USART1->RAM的数据传输 channel5
	DMA_DeInit(DMA1_Channel5);												//将DMA的通道5寄存器重设为缺省值 
	DMA1_Init.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);					//启动传输前装入实际RAM地址
	DMA1_Init.DMA_MemoryBaseAddr = (u32)m2p_u1rxbuf;            			//设置接收缓冲区首地址
	DMA1_Init.DMA_DIR = DMA_DIR_PeripheralSRC;								//数据传输方向，从外设读取到内存
	DMA1_Init.DMA_BufferSize = USART1_MAX_RX_LEN;							//DMA通道的DMA缓存的大小
	DMA1_Init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;				//外设地址寄存器不变
	DMA1_Init.DMA_MemoryInc = DMA_MemoryInc_Enable;							//内存地址寄存器递增
	DMA1_Init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;			//数据宽度为8位
	DMA1_Init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;					//数据宽度为8位
	DMA1_Init.DMA_Mode = DMA_Mode_Normal;									//工作在正常模式
	DMA1_Init.DMA_Priority = DMA_Priority_High; 							//DMA通道 x拥有高优先级 
	DMA1_Init.DMA_M2M = DMA_M2M_Disable;									//DMA通道x没有设置为内存到内存传输
	 
	DMA_Init(DMA1_Channel5,&DMA1_Init); 									//对DMA通道5进行初始化
	
	//DMA_USART1_TX  RAM->USART1的数据传输 channel4
	DMA_DeInit(DMA1_Channel4);												//将DMA的通道7寄存器重设为缺省值 
	DMA1_Init.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);					//启动传输前装入实际RAM地址
	DMA1_Init.DMA_MemoryBaseAddr = (u32)USART1_TX_BUF;              		//设置发送缓冲区首地址
	DMA1_Init.DMA_DIR = DMA_DIR_PeripheralDST; 								//数据传输方向，从内存发送到外设
	DMA1_Init.DMA_BufferSize = USART1_MAX_TX_LEN;							//DMA通道的DMA缓存的大小
	DMA1_Init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;				//外设地址寄存器不变
	DMA1_Init.DMA_MemoryInc = DMA_MemoryInc_Enable;							//内存地址寄存器递增
	DMA1_Init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;			//数据宽度为8位
	DMA1_Init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;					//数据宽度为8位
	DMA1_Init.DMA_Mode = DMA_Mode_Normal;									//工作在正常模式
	DMA1_Init.DMA_Priority = DMA_Priority_High; 							//DMA通道 x拥有高优先级 
	DMA1_Init.DMA_M2M = DMA_M2M_Disable;									//DMA通道x没有设置为内存到内存传输

	DMA_Init(DMA1_Channel4,&DMA1_Init); 									//对DMA通道4进行初始化
	
	//DMA1通道5 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;				//NVIC通道设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ;				//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;						//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);											//根据指定的参数初始化NVIC寄存器
 
	//DMA1通道4 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;				//NVIC通道设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ;				//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;						//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);											//根据指定的参数初始化NVIC寄存器

	DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);							//开USART1 Rx DMA中断
	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);							//开USART1 Tx DMA中断

	DMA_Cmd(DMA1_Channel5,ENABLE);           								//使DMA Rx 5开始工作，数据接受通道待命
	DMA_Cmd(DMA1_Channel4,DISABLE);           								//使DMA Tx 4停止工作，因为一旦打开通道就往外发送数据
	 
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);        					//开启串口DMA发送
	USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);        					//开启串口DMA接收
}
void USART1withDMA_Init(unsigned long baudrate)
{
	//GPIO端口设置
 	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure; 
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//使能USART1，GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//USART1_TX   GPIOA.2初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;										//PA.9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;									//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;								//GPIO速率50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);											//初始化GPIOA.9
	
	//USART1_RX	  GPIOA.3初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;										//PA.10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;							//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);											//初始化GPIOA.10
	 
	//USART 初始化设置
	USART_InitStructure.USART_BaudRate = baudrate;									//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;						//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;							//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No ;							//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;					//收发模式
	USART_Init(USART1, &USART_InitStructure); 										//初始化串口2
	
	//中断开启设置
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);									//开启检测串口空闲状态中断
	USART_ClearFlag(USART1,USART_FLAG_TC);											//清除USART1标志位
	
	USART_Cmd(USART1, ENABLE);														//使能串口1
	
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;								//NVIC通道设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;						//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;								//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;									//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);													//根据指定的参数初始化NVIC寄存器
	
	DMA_FOR_USART1_Init();																//DMA1_USART1初始化
}
//DMA 发送应用源码
void DMA_USART1_Tx_Data(u8 *buffer, u32 size)
{
	while(USART1_TX_FLAG);						//等待上一次发送完成（USART1_TX_FLAG为1即还在发送数据）
	USART1_TX_FLAG=1;							//USART1发送标志（启动发送）
	DMA1_Channel4->CMAR  = (uint32_t)buffer;	//设置要发送的数据地址
	DMA1_Channel4->CNDTR = size;    			//设置要发送的字节数目
	DMA_Cmd(DMA1_Channel4, ENABLE);				//开始DMA发送
}

//DMA1通道7中断
void DMA1_Channel4_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC4)!= RESET)	//DMA发送通道完成标志
	{
		DMA_ClearITPendingBit(DMA1_IT_TC4); 	//清除中断标志 
		USART_ClearFlag(USART1,USART_FLAG_TC);	//清除串口1的标志位
		DMA_Cmd(DMA1_Channel4, DISABLE );   	//关闭USART1 TX DMA1 所指示的通道
		USART1_TX_FLAG=0;						//USART1发送标志(关闭)
	}
}
//串口2中断函数
void USART1_IRQHandler(void)                	
{
	int i;
	u8 *p;
	u8 USART1_RX_LEN = 0;											//接收数据长度
	if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)			//串口1空闲中断
	{
		USART_ReceiveData(USART1); 									//清除串口1空闲中断IDLE标志位
		USART_ClearFlag(USART1,USART_FLAG_TC);						//清除USART1标志位
		DMA_Cmd(DMA1_Channel5, DISABLE );   						//关闭USART1 TX DMA1 所指示的通道
		USART1_RX_LEN = USART1_MAX_RX_LEN - DMA1_Channel5->CNDTR;	//获得接收到的字节数
		if(m2p_witchbuf)                        						//之前用的u2rxbuf，切换为u1rxbuf
		{
			p=m2p_u2rxbuf;												//先保存前一次数据地址再切换缓冲区
			DMA1_Channel5->CMAR=(u32)m2p_u1rxbuf;						//切换为u1rxbuf缓冲区地址
			m2p_witchbuf=0;                     						//下一次切换为u2rxbuf
		}else                               						//之前用的u1rxbuf，切换为u2rxbuf
		{
			p=m2p_u1rxbuf;												//先保存前一次数据地址再切换缓冲区
			DMA1_Channel5->CMAR=(u32)m2p_u2rxbuf;						//切换为u2rxbuf缓冲区地址
			m2p_witchbuf=1;                     						//下一次切换为u1rxbuf
		}
		DMA1_Channel5->CNDTR = USART1_MAX_RX_LEN;					//DMA通道的DMA缓存的大小
		DMA_Cmd(DMA1_Channel5, ENABLE);     						//使能USART1 TX DMA1 所指示的通道
		
		//******************↓↓↓↓↓这里作数据处理↓↓↓↓↓******************//
		
		for(i=0;i<M2PSerial_CmdUnit;i++)
		{
			M2PSerial_RxCmd[i]=p[i];
		}
		USART1_RX_FLAG=1;
		
		//******************↑↑↑↑↑这里作数据处理↑↑↑↑↑******************//
		
  }
}

void m2p_printf(char *format, ...)
{
	//VA_LIST 是在C语言中解决变参问题的一组宏，所在头文件：#include <stdarg.h>，用于获取不确定个数的参数。
	va_list arg_ptr;														//实例化可变长参数列表
	
	while(USART1_TX_FLAG);													//等待上一次发送完成（USART1_TX_FLAG为1即还在发送数据）
	
	va_start(arg_ptr, format); 												//初始化可变参数列表，设置format为可变长列表的起始点（第一个元素）
	
	// USART1_MAX_TX_LEN+1可接受的最大字符数(非字节数，UNICODE一个字符两个字节), 防止产生数组越界
	vsnprintf((char*)USART1_TX_BUF, USART1_MAX_TX_LEN+1, format, arg_ptr);	//从USART1_TX_BUF的首地址开始拼合，拼合format内容；USART1_MAX_TX_LEN+1限制长度，防止产生数组越界
	
	va_end(arg_ptr);														//注意必须关闭
 
	DMA_USART1_Tx_Data(USART1_TX_BUF,strlen((const char*)USART1_TX_BUF));	//发送USART1_TX_BUF内容
}



